package com.grape.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.grape.constants.Constants;
import com.grape.domain.BaseDomain;
import com.grape.error.BusinessException;
import com.grape.result.R;
import com.grape.utils.AssertUtil;
import com.grape.utils.HumpUtil;
import com.grape.utils.ReflexUtil;
import com.grape.utils.ThreadLocalUtil;
import com.grape.vo.BaseVo;
import com.grape.wrapper.BaseWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.function.Consumer;

import static com.grape.result.R.selectSuccess;


/**
 * 公共Service基类
 * @author  putao
 * @email   2628279194@qq.com
 */
public interface BaseService<T extends BaseDomain> extends IService<T> {

    /**
     * 检查对象中对应属性是否重复
     * @param consumer      消费查询条件器
     * @param t             对象
     * @param column        属性, 下划线形式
     * @return              对象
     */
    default T checkIsRepeat(Consumer<QueryWrapper<T>> consumer, T t, String column, String message) {
        QueryWrapper<T> queryWrapper = new BaseWrapper<T>().init().eq(column, ReflexUtil.getValueByName(t, HumpUtil.lineToHump(column)));
        if (consumer != null) {
            consumer.accept(queryWrapper);
        }
        if (StringUtils.isNotBlank(t.getId())) {
            queryWrapper.ne(Constants.ID, t.getId());
        }
        List<T> list = this.list(queryWrapper);
        if (CollectionUtil.isNotEmpty(list)) {
            throw new BusinessException(StringUtils.isNotBlank(message) ? message : Constants.INSERT_VALUE_REPEAT);
        }
        return t;
    }

    /**
     * 根据第一个参数是否为空决定返回是否查询成功
     * @param t         判断的对象 一般是查询出来的对象
     * @param object    其他
     * @return          接口通用结果对象
     */
    default R<?> returnObject(T t, Object object) {
        if (ObjectUtil.isEmpty(t)) {
            return R.selectNotFound(object, null);
        }
        return selectSuccess(t, object);
    }

    /**
     * 根据第一个集合是否为空或者长度是否为0决定返回是否查询成功
     * @param tList     判断的对象 一般是查询出来的对象
     * @param object    其他
     * @return          接口通用结果对象
     */
    default R<?> returnObject(List<T> tList, Object object) {
        if (CollectionUtil.isEmpty(tList)) {
            return R.selectNotFound(object, null);
        }
        return selectSuccess(tList, object);
    }

    /**
     * 检查对象中对应属性是否为空和是否重复.
     * @param id            更新操作时重复判断 过滤自身数据
     * @param queryWrapper  查询条件器
     * @param t             对象 必须是包含属性的对象，继承属性不行
     * @param column        属性, 下划线形式
     * @param repeatMessage 重复的提示信息
     * @param nullMessage   空置的提示信息
     * @param anotherColumn 查询时的其他条件
     * @param anotherValue  查询时的其他条件
     */
    default void checkIsEmptyAndRepeat(String id, QueryWrapper<T> queryWrapper, T t, String column, String repeatMessage, String nullMessage, String anotherColumn, String anotherValue) {
        Object valueByName = ReflexUtil.getValueByName(t, HumpUtil.lineToHump(column));
        AssertUtil.hasText(valueByName + "", nullMessage);
        List<T> list = this.list(queryWrapper);
        if (CollectionUtil.isNotEmpty(list)) {
            throw new BusinessException(StringUtils.isNotBlank(repeatMessage) ? repeatMessage : Constants.INSERT_VALUE_REPEAT);
        }
    }

    /**
     * 检查对象中对应属性是否为空
     * @param t         对象
     * @param columns   属性, 驼峰式
     */
    default void checkColumnIsEmpty(T t, String... columns) throws NoSuchFieldException, IllegalAccessException {
        if (ObjectUtil.isEmpty(columns) || columns.length == 0) {
            throw new BusinessException(Constants.REFLECT_CHECK_EMPTY_COLUMN_ARRAY_EMPTY);
        }
        for (String column : columns) {
            if (StringUtils.isNotBlank(column)) {
                continue;
            }
            Class<?> aClass = t.getClass();
            Field declaredField = aClass.getDeclaredField(column);
            declaredField.setAccessible(true);
            AssertUtil.hasText(declaredField.get(t), declaredField.getName() + "不能为空");
        }
    }

    /**
     * 创建待删除标记条件查询构造器
     * @return      查询构造器对象
     */
    default QueryWrapper<T> createWrapperAndDelFlag() {
        QueryWrapper<T> wrapper = this.createWrapper();
        return wrapper.eq(Constants.DEL_FLAG, BaseDomain.DEL_FLAG_NORMAL);
    }

    /**
     * 根据用户id创建查询构造器
     * @return  查询构造器对象
     */
    default QueryWrapper<T> createWrapperWithUserId(String userId) {
        QueryWrapper<T> wrapper = this.createWrapper();
        return wrapper.eq(Constants.DEL_FLAG, BaseDomain.DEL_FLAG_NORMAL).eq(Constants.CREATE_ID, userId);
    }

    /**
     * 根据id创建查询构造器
     * @return  查询构造器对象
     */
    default QueryWrapper<T> createWrapper(){
        return new QueryWrapper<T>();
    }

    /**
     * 根据id创建查询构造器
     * @param id    单据id
     * @return      查询构造器对象
     */
    default QueryWrapper<T> createWrapperById(String id){
        QueryWrapper<T> wrapper = this.createWrapperAndDelFlag();
        if (com.grape.utils.StringUtils.isBlank(id)) {
            throw new BusinessException("参数异常");
        }
        return wrapper.eq(Constants.ID, id);
    }

    /**
     * 根据ids创建查询构造器
     * @param ids   单据ids
     * @return      查询构造器对象
     */
    default QueryWrapper<T> createWrapperByIds(String ids){
        QueryWrapper<T> wrapper = this.createWrapperAndDelFlag();
        if (com.grape.utils.StringUtils.isBlank(ids)) {
            throw new BusinessException("参数异常");
        }
        if (CollectionUtil.isEmpty(com.grape.utils.StringUtils.convertList(ids))) {
            throw new BusinessException("参数异常");
        }
        return wrapper.in(Constants.ID, com.grape.utils.StringUtils.convertList(ids));
    }

    /**
     * 默认修改时间倒序
     * @param queryWrapper  查询构造器
     * @return              查询构造器对象
     */
    default QueryWrapper<T> orderByModifyTimeDesc(QueryWrapper<T> queryWrapper){
        return queryWrapper.orderByDesc(Constants.MODIFY_TIME);
    }

    /**
     * 分页
     * @param baseVo    分页对象
     * @return          分页结果集合
     */
    default List<T> listPage(BaseVo baseVo) {
        QueryWrapper<T> wrapper = new BaseWrapper<T>().init();
        wrapper.like(Strings.isNotBlank(baseVo.getSearch()), Constants.NAME, baseVo.getSearch());
        wrapper.eq(com.grape.utils.StringUtils.isNotBlank(baseVo.getColumnName())
                && com.grape.utils.StringUtils.isNotBlank(baseVo.getSelect()), baseVo.getColumnName(), baseVo.getSelect());
        wrapper.apply(StringUtils.isNotBlank(baseVo.getSql()), baseVo.getSql())
                .orderByDesc(Constants.CREATE_TIME);
        return this.list(wrapper);
    }

    /**
     * 分页
     * @param baseVo    分页对象
     * @return          分页结果集合
     */
    default PageInfo<T> page(BaseVo baseVo, Consumer<BaseVo> consumer) {
        Page<T> pages = PageHelper.startPage(baseVo.getPageNum(), baseVo.getPageSize());
        QueryWrapper<T> wrapper = new BaseWrapper<T>().init();
        if (consumer != null) {
            consumer.accept(baseVo);
        }
        wrapper.like(Strings.isNotBlank(baseVo.getSearch()), Constants.NAME, baseVo.getSearch());
        wrapper.eq(com.grape.utils.StringUtils.isNotBlank(baseVo.getColumnName())
                && com.grape.utils.StringUtils.isNotBlank(baseVo.getSelect()), baseVo.getColumnName(), baseVo.getSelect());
        wrapper.apply(StringUtils.isNotBlank(baseVo.getSql()), baseVo.getSql())
                .orderByDesc(Constants.CREATE_TIME);
        this.list(wrapper);
        return pages.toPageInfo();
    }

    /**
     * 分页
     * @param baseVo    分页对象
     * @return          分页结果集合
     */
    default List<T> listPageByDelFlag(BaseVo baseVo) {
        QueryWrapper<T> wrapper = new BaseWrapper<T>().init();
        wrapper.like(Strings.isNotBlank(baseVo.getSearch()), Constants.NAME, baseVo.getSearch());
        wrapper.eq(com.grape.utils.StringUtils.isNotBlank(baseVo.getColumnName())
                && com.grape.utils.StringUtils.isNotBlank(baseVo.getSelect()), baseVo.getColumnName(), baseVo.getSelect())
                .apply(StringUtils.isNotBlank(baseVo.getSql()), baseVo.getSql())
                .eq(Constants.DEL_FLAG, Constants.ZERO_STR)
                .orderByDesc(Constants.MODIFY_TIME);
        return this.list(wrapper);
    }

    /**
     * 分页
     * @param baseVo    分页对象
     * @return          分页结果集合
     */
    default List<T> listAllPage(BaseVo baseVo) {
        QueryWrapper<T> wrapper = new QueryWrapper<T>();
        wrapper.eq(StringUtils.isNotBlank(baseVo.getUserId()), Constants.USER_ID, baseVo.getUserId())
                .like(Strings.isNotBlank(baseVo.getSearch()), Constants.NAME, baseVo.getSearch())
                .apply(StringUtils.isNotBlank(baseVo.getSql()), baseVo.getSql())
                .orderByDesc(Constants.MODIFY_TIME);
        return this.list(wrapper);
    }

    /**
     * 修改
     * @param baseDomain    待修改对象
     * @return              当前对象
     */
    default T baseUpdate(T baseDomain){
        baseDomain.updateInit();
        this.updateById(baseDomain);
        return baseDomain;
    }

    /**
     * 新增
     * @param baseDomain    待新增对象
     * @return              当前对象
     */
    default T baseInsert(T baseDomain){
        baseDomain.insertInit();
        this.save(baseDomain);
        return baseDomain;
    }

    /**
     * 删除
     * @param ids   id，多个时以,分隔
     * @return      删除条数
     */
    default int baseDelete(String ids){
        List<String> idList = com.grape.utils.StringUtils.convertList(ids);
        int number = 0;
        if (CollectionUtil.isNotEmpty(idList)) {
            Collection<T> userList = this.listByIds(idList);
            if (CollectionUtil.isNotEmpty(userList)) {
                for (T t : userList) {
                    if (BaseDomain.DEL_FLAG_DELETE.equals(t.getDelFlag())) {
                        return -1;
                    }
                    t.setDelFlag(BaseDomain.DEL_FLAG_DELETE);
                    number++;
                }
                this.updateBatchById(userList);
            }
        }
        return number;
    }


    /**
     * 分页列表
     * @param baseVo    分页参数对象
     * @return          分页结果
     */
    default PageInfo<T> pageList(BaseVo baseVo) {
        Page<T> pages = PageHelper.startPage(baseVo.getPageNum(), baseVo.getPageSize());
        this.listPage(baseVo);
        return pages.toPageInfo();
    }


    /**
     * 分页列表
     * @param baseVo    分页参数对象
     * @return          分页结果
     */
    default PageInfo<T> pageListByDelFlag(BaseVo baseVo) {
        Page<T> pages = PageHelper.startPage(baseVo.getPageNum(), baseVo.getPageSize());
        this.listPageByDelFlag(baseVo);
        return pages.toPageInfo();
    }

    /**
     * 根据id查询数据
     * @param id    单据id
     * @return      根据id查询的数据
     */
    default T getByIdForDelFlag(String id) {
        return this.getOne(new BaseWrapper<T>().initById(id));
    }

    /**
     * 根据id查询数据并断言结果
     * @param id    单据id
     * @return      根据id查询的数据
     */
    default T getByIdForDelFlagAndAssert(String id) {
        T t = this.getOne(new BaseWrapper<T>().initById(id));
        if (t == null) {
            throw new BusinessException("数据不存在或已删除");
        }
        return t;
    }

    /**
     * 根据ids查询数据
     * @param ids       ids
     * @return          根据ids查询的数据
     */
    default List<T> getByIdsForDelFlag(String ids) {
        return this.list(new BaseWrapper<T>().initByIds(ids));
    }

    /**
     * 根据ids查询并作断言
     * @param ids       ids
     * @return          根据ids查询的数据
     */
    default List<T> getByIdsForDelFlagAndAssert(String ids) {
        List<T> tList = this.list(new BaseWrapper<T>().initByIds(ids));
        if (CollectionUtil.isEmpty(tList)) {
            throw new BusinessException("数据不存在或已删除");
        }
        return tList;
    }

    /**
     * 根据id更新单据审核状态
     * @param id        话题id
     * @param status    审核状态
     */
    default void updateStatusById(String id, String status) {
        UpdateWrapper<T> postUpdateWrapper = new UpdateWrapper<>();
        postUpdateWrapper.set(Constants.STATUS, status);
        postUpdateWrapper.eq(Constants.ID, id);
        this.update(postUpdateWrapper);
    }

    /**
     * 审核回调后前置检查
     * @param id            单据id
     * @param status        审核状态
     * @param errorMessage  数据为空时错误信息
     * @return              当前泛型对象
     */
    default T preAuditInspection(String id, String status, String errorMessage) {
        AssertUtil.hasText(id, errorMessage + ", 单据id不能为空");
        AssertUtil.hasText(status, errorMessage + ", 单据审核状态不能为空");
        return this.getByIdForDelFlag(id);
    }

    /**
     * 根据用户id和字段名修改值
     * @param userId            用户id
     * @param columnName        字段名
     * @param columnValue       字段值
     */
    default void updateByWrapper(String userId, String columnName, String columnValue, String userColumnName) {
        if (com.grape.utils.StringUtils.isBlank(userId) || Constants.USER_ID.equals(columnName)) {
            return;
        }
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<T>()
                .set(columnName, columnValue).set(Constants.MODIFY_TIME, new Date())
                .eq(userColumnName, userId);
        this.update(updateWrapper);
    }

    /**
     * 查询单个拼接用户id
     * @return  单个
     */
    default T getOneAppendUserId() {
        return this.getBaseMapper().selectOne(new BaseWrapper<T>().initUserId(ThreadLocalUtil.getUserId()));
    }

    /**
     * 查询集合拼接用户id
     * @return  集合
     */
    default List<T> listAppendUserId() {
        return this.getBaseMapper().selectList(new BaseWrapper<T>().initUserId(ThreadLocalUtil.getUserId()));
    }

    /**
     * 查询单个拼接用户id和删除标记
     * @return  单个
     */
    default T getOneAppendDelAndUserId() {
        return this.getBaseMapper().selectOne(new BaseWrapper<T>().initDelFlagAndUserId(ThreadLocalUtil.getUserId()));
    }

    /**
     * 查询集合拼接用户id和删除标记
     * @return  集合
     */
    default List<T> listAppendDelAndUserId() {
        return this.getBaseMapper().selectList(new BaseWrapper<T>().initDelFlagAndUserId(ThreadLocalUtil.getUserId()));
    }

    /**
     * 查询集合拼接删除标记
     * @return  集合
     */
    default List<T> listAppendDelFlag() {
        return this.getBaseMapper().selectList(new BaseWrapper<T>().init(ThreadLocalUtil.getUserId()));
    }

    /**
     * 查询集合拼接用户id和删除标记
     * @return  集合
     */
    default List<T> listAppendDelAndUserId(Consumer<QueryWrapper<T>> consumer) {
        QueryWrapper<T> queryWrapper = new BaseWrapper<T>().initDelFlagAndUserId(ThreadLocalUtil.getUserId());
        if (consumer != null) {
            consumer.accept(queryWrapper);
        }
        return this.getBaseMapper().selectList(queryWrapper);
    }

}
